package com.gzhu.knowledgeAdmin.common.utils;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.resource.InputStreamResource;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gzhu.knowledgeAdmin.common.config.GoFastDfsConfig;
import com.gzhu.knowledgeAdmin.common.config.SSHConfig;
import com.gzhu.knowledgeAdmin.common.vo.GoFastDfsUploadFileVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author Administrator
 * @apiNote 文件服务器工具类
 */
@Slf4j
@Component
public class GoFastDfsUtil {

    @Autowired
    private GoFastDfsConfig configVO;


    @Autowired
    private SSHConfig sshConfig;
    /**
     * 上传文件服务器
     */
    private static final String FILE_UPLOAD_URL = "/upload";

    /**
     * 删除文件服务器文件
     */
    private static final String FILE_DELETE_URL = "/delete";

    /**
     * 获取文件信息
     */
    private static final String GET_FILE_INFO_URL = "/get_file_info";

    /**
     * 查询文件数量
     */
    private static final String FILE_STAT_URL = "/stat";



    /**
     * 根据文件的文件服务器路径删除文件服务器上的文件
     *
     * @param url
     * @return
     */
    public void deleteFileByUrl(String url) throws MalformedURLException {
        // 校验参数是否为空
        checkCondition(url);
        URL newUrl = new URL(url);
        String path = newUrl.getPath();

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("path", path);
        String servicePath = getServicePath();
        String postResult = HttpUtil.post(servicePath + FILE_DELETE_URL, paramsMap);
        log.info("postResult:{}", postResult);

    }


    /**
     * 根据文件路径获取文件的byte数组
     *
     * @param filePath
     * @return
     */
    public byte[] getFileBytes(String filePath) {
        BufferedInputStream bin = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] resultByte = null;
        try {
            // 统一资源并将filePath中的空格替换为特殊符号
            URL url = new URL(filePath.replaceAll(" ", "%20"));
            // 连接类的父类,抽象类
            URLConnection urlConnection = url.openConnection();
            // http的连接类
            HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
            // 设置超时时间
            httpURLConnection.setConnectTimeout(1000 * 5);
            // 设置请求方式,默认是GET
            httpURLConnection.setRequestMethod("POST");
            // 设置字符编码
            httpURLConnection.setRequestProperty("Charset", "UTF-8");
            // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)
            httpURLConnection.connect();
            // 从请求中获取数据
            bin = new BufferedInputStream(httpURLConnection.getInputStream());
            byte[] bytes = new byte[1024 * 4];
            int n = 0;
            while (-1 != (n = bin.read(bytes))) {
                bos.write(bytes, 0, n);
            }
            resultByte = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bin != null) {
                    bin.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultByte;
    }

    /**
     * 根据文件服务器的文件路径下载文件到本地
     *
     * @param url      文件服务器的文件地址
     * @param response
     */
    public void downloadFile(String url, HttpServletResponse response) throws MalformedURLException, URISyntaxException {

        // 获取文件名
        URL newUrl = new URL(url.replaceAll(" ", "%20"));
        String path = newUrl.getPath();
        String fileName = path.substring(path.lastIndexOf("/")+1);

        // TODO 部署到docker中，需要重写URL
        // url = reWriteDomain(url, "fastdfs");

        // URL加上请求参数download=1,设置为可下载
        url = url.concat("?download=1");

        // 获取文件字节数组
        byte[] data = getFileBytes(url);

        response.reset();
        response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
        response.addHeader("Content-Length", "" + data.length);
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setContentType("application/octet-stream;charset=UTF-8");

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 读取linux服务器本地文件储存到文件服务器中，并删除linux服务器本地文件
     * @param srcFilePath 完整文件路径，包括文件名
     * @param desFilePath 目标储存路径，不包括文件名
     * @return
     */
    public  GoFastDfsUploadFileVo uploadFromLinux(String srcFilePath,String desFilePath) {
        Sftp sftp = null;
        FileInputStream fileInputStream = null;
        GoFastDfsUploadFileVo uploadFileVo = null;

        try {
            /*
             * 一、获取文件的输入流
             * 1. 连接上linux服务器22号端口
             * 2. 获取文件流
            */
            // 连接上
            sftp = JschUtil.createSftp(sshConfig.getIp(), sshConfig.getPort(), sshConfig.getUser(), sshConfig.getPass());
            // 使用系统临时目录
            String tempDir = System.getProperty("java.io.tmpdir");
            String tempFileName = IdUtil.simpleUUID() + ".tmp";
            File tempFile = new File(tempDir, tempFileName);
            // 下载Linux文件
            sftp.download(srcFilePath,tempFile);

            // 生成文件名
            String fileName = generateFileName(srcFilePath);


            fileInputStream = new FileInputStream(tempFile);

            InputStreamResource isr = new InputStreamResource(fileInputStream,fileName);



            // 二、上传到文件服务器
            uploadFileVo = getGoFastDfsUploadFileVo(isr, desFilePath);


            // 三、删除linux服务器本地文件和临时文件
            sftp.delFile(srcFilePath);
            tempFile.delete();

        } catch (FileNotFoundException | MalformedURLException | URISyntaxException e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            sftp.close();
        }

        return uploadFileVo;

    }

    public String generateFileName(String srcFilePath) {

        String fileFormat = "";
        if(StringUtils.hasLength(srcFilePath)){
            // 获取原始文件格式(带上".")
            int index = srcFilePath.lastIndexOf(".");
            if(index!=-1){
                fileFormat = srcFilePath.substring(index);
            }
        }
        // 生成文件名
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        return uuid+fileFormat;
    }

    /**
     * 将本地文件上传到文件服务器
     * @param srcFilePath 本地文件路径
     * @return
     */
    public GoFastDfsUploadFileVo uploadFromLocal(String srcFilePath) throws Exception {
        FileReader fileReader = new FileReader(srcFilePath);
        String fileName = generateFileName(srcFilePath);

        InputStreamResource inputStreamResource = new InputStreamResource(fileReader.getInputStream(), fileName);
        return uploadFile(inputStreamResource);
    }
    public  GoFastDfsUploadFileVo uploadFile(InputStreamResource inputStreamResource) throws Exception {
        return getGoFastDfsUploadFileVo(inputStreamResource,null);
    }
    /**
     * 文件上传文件服务器工具类
     *
     * @param file
     * @return
     */
    public   GoFastDfsUploadFileVo uploadFile(MultipartFile file) throws Exception {

        // 获取文件的输入流
        String originalFilename = file.getOriginalFilename();
        String fileName = generateFileName(originalFilename);
        InputStreamResource isr = new InputStreamResource(file.getInputStream(), fileName);


        return getGoFastDfsUploadFileVo(isr,null);
    }

    /**
     * 上传文件
     * @param isr 输入流
     * @param desFilePath 目标相对储存路径，后面会再加上时间日期
     * @return
     */
    private GoFastDfsUploadFileVo getGoFastDfsUploadFileVo(InputStreamResource isr,String desFilePath) throws MalformedURLException, URISyntaxException {
        Map<String, Object> paramsMap = new HashMap<>();
        //存储路径按照期日格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String format = sdf.format(new Date());
        // 如果指定了存放路径，再拼接上时间日期
        if(StringUtils.hasLength(desFilePath)){
            StringBuilder stringBuilder = new StringBuilder(desFilePath);
            stringBuilder.append(File.separator).append(format);
            format = stringBuilder.toString();
        }
        paramsMap.put("file", isr);
        paramsMap.put("output", "json");
        paramsMap.put("path", format);

        // 获取文件系统路径
        String servicePath = getServicePath();
        String postResult = HttpUtil.post(servicePath + FILE_UPLOAD_URL, paramsMap);
        log.info("postResult:{}", postResult);
        JSONObject jsonObject = JSONObject.parseObject(postResult);
        GoFastDfsUploadFileVo fileResult = JSON.toJavaObject(jsonObject, GoFastDfsUploadFileVo.class);

        // TODO 部署到docker中，需要重写域名
         String s = reWriteDomain(fileResult.getUrl(), configVO.getIp().substring(7));
         fileResult.setUrl(s);

        return fileResult;
    }

    private String reWriteDomain(String originalUrl,String domain) throws MalformedURLException, URISyntaxException {
        // 重写域名
        String newDomain = domain + ":" + configVO.getPort();

        URL url = new URL(originalUrl);
        URI uri = new URI(url.getProtocol(), newDomain, url.getPath(), url.getQuery(), url.getRef());
        String replacedUrl = uri.toURL().toString();

        return replacedUrl;
    }

    private String reWriteDomain(String originalUrl) throws MalformedURLException, URISyntaxException {
        URL url = new URL(originalUrl);

        url.getProtocol();
        url.getPath();

        return null;
    }

    /**
     * 文件上传文件服务器工具类
     *
     * @param file
     * @return
     */
    public GoFastDfsUploadFileVo uploadFile(MultipartFile file, String filePath) throws IOException, URISyntaxException {
        // 获取文件的输入流
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String fileName = uuid + file.getOriginalFilename();

        return this.uploadFile(file, fileName, filePath);
    }

    /**
     * 文件上传文件服务器工具类
     *
     * @param file
     * @return
     */
    private GoFastDfsUploadFileVo uploadFile(MultipartFile file, String fileName, String filePath) throws IOException, URISyntaxException {

        // 获取文件的输入流
        InputStreamResource isr = new InputStreamResource(file.getInputStream(), fileName);

        Map<String, Object> paramsMap = new HashMap<>();
        //存储路径按照日期格式
        paramsMap.put("file", isr);
        paramsMap.put("output", "json");
        paramsMap.put("path", filePath);

        // 获取文件系统路径
        String servicePath = getServicePath();
        String postResult = HttpUtil.post(servicePath + FILE_UPLOAD_URL, paramsMap);
        log.info("postResult:{}", postResult);
        JSONObject jsonObject = JSONObject.parseObject(postResult);
        GoFastDfsUploadFileVo fileResult = JSON.toJavaObject(jsonObject, GoFastDfsUploadFileVo.class);

        // TODO 部署到docker中，需要重写域名
         String s = reWriteDomain(fileResult.getUrl(), configVO.getIp().substring(7));
         fileResult.setUrl(s);

        return fileResult;
    }


    /**
     * 拼接文件服务器路径
     *
     * @return
     */
    public String getServicePath() {
        return configVO.getIp() + ":" + configVO.getPort();
    }

    /**
     * 校验参数
     *
     * @param condition
     */
    public void checkCondition(String condition) {
        if (StrUtil.isEmpty(condition)) {
            throw new RuntimeException("文件的md5或path不能为空,请输入文件的md5或path值!");
        }
    }

    /**
     * 将文件服务器中的文件保持到本地
     * @param fileUrl
     */
    public void saveToLocal(String fileUrl,String desFilePath) {
        // 获取文件字节数组
        byte[] data = getFileBytes(fileUrl);
        FileOutputStream fileOutputStream = null;
        // 获取文件名
        String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
        try {
            StringBuilder stringBuilder = new StringBuilder(desFilePath);
            stringBuilder.append(File.separator).append(fileName);
             fileOutputStream = new FileOutputStream(stringBuilder.toString());
            fileOutputStream.write(data);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}
